﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Log;

namespace ConAppCore.Test
{
    internal class TestSpinWaiter
    {

        public static void Test()
        {
            try
            {
                //TestThreadSleepTime();

                TestSpinWaitMilliseconds();
                TestSpinWaitNanoseconds();

                //TestThreadSpinWait();
                //TestSpinWaiterSpinWait();


                TestAutoResetEventTime();

                //TestCalTime();
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }

        private static void TestCalTime()
        {
            var ts1 = DateTime.Parse("2023-01-12 21:46:09") - DateTime.Parse("2023-01-12 17:09:56");
            var ts2 = DateTime.Parse("2023-01-13 02:22:21") - DateTime.Parse("2023-01-12 21:46:09");
            var ts3 = DateTime.Parse("2023-01-13 06:58:34") - DateTime.Parse("2023-01-13 02:22:21");
            Console.WriteLine($"ts1:{ts1.TotalHours}h,ts2:{ts2.TotalHours}h,ts3:{ts3.TotalHours}h");
        }


        private static void TestAutoResetEventTime()
        {
            //AutoResetEvent的等待切换几乎没用时间,底层实现大概率是发送通知的线程直接接管了执行,并没有重新给等待线程调度分配时间片
            bool runing = true;
            bool enterTheading = true;
            AutoResetEvent eventHandler = new AutoResetEvent(false);
            bool hasSignal = false;

            Task.Factory.StartNew(() =>
            {
                enterTheading = false;
                int count = 0;

                while (runing)
                {
                    if (hasSignal)
                    {
                        hasSignal = false;

                        try
                        {
                            count++;
                            if (count > 10)
                            {
                                SpinWaiter.SpinWaitMilliseconds(count);
                            }

                            eventHandler.Set();
                        }
                        catch (ObjectDisposedException)
                        {
                            break;
                        }
                    }
                }
            });
            while (enterTheading)
            {

            }

            Stopwatch stopwatch = new Stopwatch();
            for (int i = 1; i <= 50; i++)
            {
                stopwatch.Restart();
                hasSignal = true;
                if (eventHandler.WaitOne(i))
                {
                    stopwatch.Stop();
                    Console.WriteLine($"第{i}AutoResetEvent.WaitOne收到消息时间:{i}ms,实际:{stopwatch.Elapsed.TotalMilliseconds}ms");
                }
                else
                {
                    stopwatch.Stop();
                    Console.WriteLine($"第{i}AutoResetEvent.WaitOne收到超时时间:{i}ms,实际:{stopwatch.Elapsed.TotalMilliseconds}ms");
                }
            }
            runing = false;

            eventHandler.Dispose();
        }

        private static void TestThreadSleepTime()
        {
            Stopwatch stopwatch = new Stopwatch();
            for (int i = 1; i <= 50; i++)
            {
                stopwatch.Restart();
                Thread.Sleep(i);
                stopwatch.Stop();
                Console.WriteLine($"第{i}次Thread.Sleep时间:{i}ms,实际:{stopwatch.Elapsed.TotalMilliseconds}ms");
            }
        }

        private static void TestSpinWaiterSpinWait()
        {
            Console.WriteLine("--------------------------------------------------------------");

            //Stopwatch stopwatch = new Stopwatch();
            //for (int i = 1; i <= 50; i++)
            //{
            //    stopwatch.Restart();
            //    ThreadEx.SpinWait(i);
            //    stopwatch.Stop();
            //    Console.WriteLine($"第{i}次SpinWait时间:{stopwatch.Elapsed.TotalMilliseconds}ms");
            //}

            double ret;
            for (int i = 1; i <= 50; i++)
            {
                //ret = SpinWaiter.SpinWaitMilliseconds(i);
                ret = SpinWaiter.SpinWait100Nanoseconds(i * 1000000);
                Console.WriteLine($"第{i}次SpinWait时间:{ret / 1000000}ms");
            }
        }
        private static void TestThreadSpinWait()
        {
            Stopwatch stopwatch = new Stopwatch();
            for (int i = 1; i <= 50; i++)
            {
                stopwatch.Restart();
                while (stopwatch.Elapsed.TotalMilliseconds < i)
                {
                    Thread.SpinWait(5);
                }
                stopwatch.Stop();
                Console.WriteLine($"第{i}次SpinWait时间:{stopwatch.Elapsed.TotalMilliseconds}ms");
            }
        }



        private static void TestSpinWaitNanoseconds()
        {
            double nanosecond100s, ret;
            Stopwatch stopwatch = new Stopwatch();
            long mul = 10000;
            for (int i = 1; i <= 10; i++)
            {
                nanosecond100s = i * mul;
                stopwatch.Restart();
                ret = SpinWaiter.SpinWait100Nanoseconds(nanosecond100s);
                stopwatch.Stop();
                Console.WriteLine($"第{i}次SpinWait时间:{nanosecond100s / mul}ms,结果:{ret / mul}ms,实际:{stopwatch.Elapsed.TotalMilliseconds}ms");
            }
        }

        private static void TestSpinWaitMilliseconds()
        {
            double milliseconds, ret;
            Stopwatch stopwatch = new Stopwatch();
            for (int i = 1; i <= 10; i++)
            {
                milliseconds = i;
                stopwatch.Restart();
                ret = SpinWaiter.SpinWaitMilliseconds(milliseconds);
                stopwatch.Stop();
                Console.WriteLine($"第{i}次SpinWait时间:{milliseconds}ms,结果:{ret}ms,实际:{stopwatch.Elapsed.TotalMilliseconds}ms");
            }
        }
    }
}
